package cn.cht.work.factory;

import cn.cht.work.annotation.Autowired;
import cn.cht.work.annotation.Service;
import cn.cht.work.annotation.Transactional;
import com.alibaba.druid.util.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：开启包扫描,读取注解,并将对象放到mpa
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String,Object> map = new HashMap<>();  // 存储对象


    static {

        // 任务一，通过反射技术实例化对象并且存储待用（map集合）
        //开启包扫描,扫描注解
        Reflections reflections = new Reflections("cn.cht.work");

        try {
            //获取service 注解对象
            Set<Class<?>> typesAnnotatedWith = reflections.getTypesAnnotatedWith(Service.class);
            for (Class<?> aClass : typesAnnotatedWith) {
                //实例化对象
                Object bean = aClass.newInstance();
                Service annotation = aClass.getAnnotation(Service.class);
                //根据作业要求  根据属性值 判断注解有无 value
                if (StringUtils.isEmpty(annotation.value())) {
                    //如果没有value ,则根据类名
                    String[] names = aClass.getName().split("\\.");
                    map.put(names [names.length - 1], bean);
                } else {
                    map.put(annotation.value(), bean);
                }
            }
            //获取 service 中 哪些需要 autowired 的对象
            for (Map.Entry<String, Object> objectEntry : map.entrySet()) {
                //获取对象
                String key = objectEntry.getKey();
                Object value = objectEntry.getValue();
                Class<?> aClass = value.getClass();
                //获取对象变量
                Field[] fields = aClass.getDeclaredFields();
                //遍历变量,判断是否还有Autowired注解
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class)&&field.getAnnotation(Autowired.class).required()) {
                        Class<?> type = field.getType();
                        String typename = type.getName();
                        String[] names = typename.split("\\.");
                        String name = names[names.length - 1];
                        //Autowired注解的位置需要set方法,便于aClass.getMethods()获取
                        Method[] methods = aClass.getMethods();
                        for (Method method : methods) {
                            if (method.getName().equalsIgnoreCase("set"+name)){
                                method.invoke(value,map.get(name));
                            }
                        }
                    }
                }

                //判断对象类是否持有 Transactional注解,若有则改为代理对象
                if (aClass.isAnnotationPresent(Transactional.class)) {
                    //获取代理工厂
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    //获取对象所有接口
                    Class<?>[] interfaces = aClass.getInterfaces();
                    //判断对象是否实现接口,选择不同代理
                    if (interfaces !=null && interfaces.length>0) {
                        //有接口,选用jdk代理
                        value = proxyFactory.getJdkProxy(value);
                    }else {
                        //没有接口,选择cglib
                        value = proxyFactory.getCglibProxy(value);
                    }
                }
                //把具有 Transactional 功能的替换之前的
                map.put(key,value);
            }

        }catch (Exception e){
            System.out.println("注解实现出现异常问题!!");
            e.printStackTrace();
        }




    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
